"""Base front matter validator and processor"""

import datetime
import os
import random
from dataclasses import dataclass, field
from pathlib import Path
from typing import Any, Dict, List, Union

import tomlkit
from loguru import logger

from mdtool.body.base_body import ImageReference
from mdtool.config_reader import Config

from ..error_handler import FileSystemError, ValidationError
from ..openrouter_service import OpenRouterService
from .validator import FrontMatterValidator, ValidationResult


@dataclass
class BaseFrontMatter:
    """Base class for front matter handling"""

    header_text: Union[Dict[str, Any], str] = field(default_factory=dict)
    title: str = ""
    date: str = ""
    keywords: List[str] = field(default_factory=list)
    description: str = ""
    tags: List[str] = field(default_factory=list)
    categories: List[str] = field(default_factory=list)
    banner: str = ""
    banner_imgRef: ImageReference = None
    _author: str = ""
    _source_dir: str = ""
    # Front matter delimiters
    DELIMITER = "+++\n"  # Default delimiter

    VALID_DRAFT_VALUES = {
        "true": True,
        "True": True,
        "TRUE": True,
        "false": False,
        "False": False,
        "FALSE": False,
    }

    PREDEFINED_CATEGORIES = [
        "个人观点",
        "实用总结",
        "方法论",
        "AI编程",
        "软件工程",
        "工程效率",
        "人工智能",
    ]

    def __post_init__(self):
        """Initialize validator and set fields from header_text if it's a dictionary"""
        self._raw_draft = None
        self._raw_author = None
        result = {}

        if isinstance(self.header_text, str) and self.header_text:
            try:
                # 使用tomlkit解析TOML内容
                result = tomlkit.parse(self.header_text)
            except Exception as e:
                logger.error(self.header_text, e)
                raise ValidationError(
                    f"Front matter should be toml format, and the following string is not valid: {self.header_text} .raise ValidationError from err"
                ) from e
        else:
            result = {"title": "title here"}
        self._set_fields_from_dict(result)

        # Initialize validator after setting fields
        self.validator = FrontMatterValidator()
        self._register_validation_rules()

    def auto_completion(self, body_text: str, openrouter: OpenRouterService) -> None:
        """Enhance document using AI services"""
        if not body_text:
            return

        if not self.title or self.title == "title here":
            self.title = openrouter.summarize_for_title(body_text)

        if not self.description:
            self.description = openrouter.summarize_for_subtitle(body_text)

        if not self.tags:
            self.tags = openrouter.generate_tags(body_text)

        if not self.categories:
            self.categories = [openrouter.suggest_category(body_text)]

        if not self.keywords:
            self.keywords = openrouter.generate_seo_keywords(body_text)

        if not self.banner or self.banner == "":
            self.banner = (
                f"https://picsum.photos/id/{random.randint(1, 100)}/900/300.jpg"
            )

    def _register_validation_rules(self):
        """Register basic validation rules

        This method can be overridden by subclasses to add specific validation rules.
        """
        self.validator.add_required_field("title", "Missing required field: title")
        self.validator.add_required_field("draft", "Missing required field: draft")

        def validate_format(value: Any) -> bool:
            if isinstance(value, (list, dict)):
                return True  # Skip validation for complex types
            if not value:
                return True  # Skip empty values
            return True  # Basic format validation is done during parsing

        self.validator.add_format_rule(
            "*",  # Apply to all fields
            validate_format,
            'All fields must use key="value" format',
        )

        def validate_date(value: str) -> bool:
            if not value:
                return True
            try:
                datetime.datetime.strptime(value, "%Y-%m-%d")
                return True
            except (ValueError, TypeError):
                return False

        self.validator.add_format_rule(
            "date", validate_date, "date must be in YYYY-MM-DD format"
        )

        def validate_draft(value: str) -> bool:
            if not value:
                return True
            return str(value).lower() in self.VALID_DRAFT_VALUES

        self.validator.add_format_rule(
            "draft",
            validate_draft,
            "Invalid draft value - must be one of: true, True, TRUE, false, False, FALSE (case sensitive)",
        )

        # Banner path validation
        def validate_banner(value: str) -> bool:
            if not value:
                return True
            if value.startswith(("http://", "https://")):
                return True

            # 如果是相对路径，则基于 self._source_dir 进行检查
            if not Path(value).is_absolute():
                if self._source_dir:
                    return Path(self._source_dir).joinpath(value).exists()
                else:
                    # 如果 _source_dir 未设置，则回退到基于当前工作目录的检查
                    return Path(value).exists()

            return Path(value).exists()

        self.validator.add_format_rule(
            "banner", validate_banner, "banner must be a valid image path"
        )

        def validate_tags(tags: List[str]) -> bool:
            if not tags:
                return True
            return all(" " not in tag for tag in tags)

        self.validator.add_format_rule(
            "tags", validate_tags, "Tags cannot contain spaces"
        )

        # 新增 description 字段长度校验
        def validate_description_length(value: str) -> bool:
            if not value:
                return True
            return len(value) <= 139

        self.validator.add_format_rule(
            "description",
            validate_description_length,
            "description 字段长度不能超过 100 字符",
        )

    def _set_fields_from_dict(self, header_dict: Dict[str, Any]) -> None:
        """Set fields from header dictionary

        Args:
            header_dict: Dictionary containing front matter fields
        """
        if not header_dict:
            return
        for key, value in header_dict.items():
            if hasattr(self, key):
                if key == "draft":
                    # 特殊处理draft字段
                    self._raw_draft = str(value).lower()
                elif key == "author":
                    # 特殊处理author字段
                    self._raw_author = str(value).strip()
                    self._author = self._raw_author
                elif key == "title":
                    self.title = str(value).strip()
                elif key in ["tags", "categories", "keywords"]:
                    # Handle list fields
                    if isinstance(value, str):
                        value = [
                            v.strip().strip('"')
                            for v in value.strip("[]").split(",")
                            if v.strip()
                        ]
                    setattr(self, key, value)
                else:
                    setattr(self, key, value)

    @property
    def draft(self) -> bool:
        if self._raw_draft is None:
            return True
        return (
            True if str(self._raw_draft).lower() in ["TRUE", "True", "true"] else False
        )

    @draft.setter
    def draft(self, value: str) -> None:
        """Set the draft value

        Args:
            value: Draft value as string
        """
        self._raw_draft = str(value).lower()

    @property
    def author(self) -> str:
        """Get the author value

        Returns:
            Author name or empty string if not set
        """
        return self._raw_author if self._raw_author is not None else ""

    @author.setter
    def author(self, value: str) -> None:
        """Set the author value

        Args:
            value: Author name
        """
        self._raw_author = str(value).strip()
        self._author = self._raw_author

    def validate(self) -> ValidationResult:
        """Validate front matter fields

        Returns:
            ValidationResult object containing validation issues
        """
        fields = {
            "title": self.title,
            "date": self.date,
            "tags": self.tags,
            "categories": self.categories,
            "keywords": self.keywords,
            "banner": self.banner,
            "author": self._raw_author if self._raw_author is not None else "",
            "draft": self._raw_draft if self._raw_draft is not None else "True",
            "description": self.description,
        }

        return self.validator.validate_to_result(fields)

    def check_format(self) -> list[str]:
        """Check the format of the front matter"""
        result = []
        validation_result = self.validate()
        if not validation_result.is_valid:
            # 返回所有详细的错误信息
            result.extend([issue.message for issue in validation_result.issues])
        # 验证 banner 是否存在
        if not self.getBannerImgRef().check():
            result.append(
                f"Invalid banner image: {self.getBannerImgRef().original_path}"
            )
        return result

    def getBannerImgRef(self) -> ImageReference:
        # 验证 source_dir
        if not self._source_dir:
            raise FileSystemError("Source directory is required")

        # Initialize default values
        banner = getattr(self, "banner", "")
        banner_existed = False
        banner_path = ""
        banner_external = False
        # 如果没有banner，则使用默认banner
        if not banner:
            banner = f"https://picsum.photos/id/{random.randint(1, 100)}/900/300.jpg"

        banner_external = banner.startswith("http")
        if banner_external:
            banner_path = banner
            banner_existed = True  # External banner images are considered existing
        else:
            # 使用 Path 对象处理相对路径
            banner_path = os.path.join(self._source_dir, banner)
            banner_existed = os.path.exists(banner_path)

        self.banner_imgRef = ImageReference(
            url_in_text=banner,
            original_path=banner_path,
            existed=banner_existed,
            external=banner_external,
            alt_text="banner",
        )
        return self.banner_imgRef

    def parse(self) -> Dict[str, Any]:
        """Parse front matter text into a dictionary using TOML

        Returns:
            Dictionary containing front matter fields
        """
        result = {}

        if isinstance(self.header_text, str) and self.header_text:
            try:
                # 使用tomlkit解析TOML内容
                result = tomlkit.parse(self.header_text)
                # 设置字段
                self._set_fields_from_dict(result)
                return result
            except Exception as parse_error:
                logger.error(f"Legacy parser also failed: {parse_error}")

        # 如果解析失败或没有内容，返回默认title
        result = {"title": "title here"}
        self._set_fields_from_dict(result)
        return result

    def standardize(self) -> Dict[str, Any]:
        """Standardize front matter fields

        Returns:
            Dictionary with standardized field values
        """
        result = {
            "title": self.title,
            "date": self.date,
            "author": self.author,
            "draft": self.draft,  # 使用属性getter获取正确格式的draft值
            "description": self.description,
            "banner": self.banner,
        }

        # Add list fields
        if self.tags:
            result["tags"] = self.tags
        if self.categories:
            result["categories"] = self.categories
        if self.keywords:
            result["keywords"] = self.keywords

        # Ensure date format is correct
        if "date" in result and result["date"]:
            try:
                date = datetime.datetime.strptime(result["date"], "%Y-%m-%d")
                result["date"] = date.strftime("%Y-%m-%d")
            except ValueError:
                pass  # Let validation handle errors

        # Remove empty values
        return {k: v for k, v in result.items() if v}

    def get(self, key: str, default: Any = None) -> Any:
        """Get a value from the front matter with a fallback default

        Args:
            key: The front matter key to retrieve
            default: Default value if the key doesn't exist

        Returns:
            The value for the key if it exists, otherwise the default value
        """
        key = key.lower()
        if key == "draft":
            if self._raw_draft is None:
                return "True"
            draft_value = str(self._raw_draft).lower()
            return self.VALID_DRAFT_VALUES.get(draft_value, default)

        if key == "author":
            return self._raw_author if self._raw_author is not None else default

        if hasattr(self, key):
            return getattr(self, key) or default

        return default

    def _format_list_value(self, value: List[Any]) -> str:
        """Format a list value for front matter output

        Args:
            value: List to format

        Returns:
            Formatted string representation of the list
        """
        formatted_items = []
        for item in value:
            if isinstance(item, bool):
                formatted_items.append(f'"{str(item).lower()}"')
            elif isinstance(item, str):
                formatted_items.append(f'"{item}"')
            else:
                formatted_items.append(str(item))
        return f'[{",".join(formatted_items)}]'

    def to_string(self) -> str:
        """Convert front matter to TOML string format

        Returns:
            Front matter as a string in TOML format
        """
        fields = self.standardize()

        # 创建TOML文档
        doc = tomlkit.document()

        # 添加字段到TOML文档
        for key, value in sorted(fields.items()):
            if value:  # 只添加非空值
                if key == "draft":
                    doc[key] = str(value)
                # 特殊处理列表字段
                elif isinstance(value, (list, tuple)):
                    doc[key] = value
                # 处理其他字段
                else:
                    doc[key] = value

        # 生成TOML字符串
        toml_content = tomlkit.dumps(doc)

        # 添加分隔符
        return f"{self.DELIMITER.rstrip()}\n{toml_content}{self.DELIMITER}"

    @classmethod
    def from_text(cls, text: str, config: Config = None) -> "BaseFrontMatter":
        instance = cls(header_text=text)
        instance.config = config
        return instance
